package insight.google.game.era.mgr;

import insight.google.game.era.bo.GameActionLog;
import insight.google.game.era.bo.GameRoom;
import insight.google.game.era.bo.GameUser;
import insight.google.game.era.bo.card.CharacterCard;
import insight.google.game.era.bo.card.GameCard;
import insight.google.game.era.bo.card.RoleCard;
import insight.google.game.era.bo.policy.AbstractPolicy;
import insight.google.game.era.bo.policy.PolicyFactory;
import insight.google.game.era.bo.policy.character.CharacterPolicy;
import insight.google.game.era.client.proxy.ChatClientProxyImpl;
import insight.google.game.era.client.proxy.PlayerClientProxy;
import insight.google.game.era.client.proxy.PlayerClientProxyImpl;
import insight.google.game.era.core.GameCenterManager;
import insight.google.game.era.core.Util;
import insight.google.game.era.core.exception.InsightException;
import insight.google.game.era.core.hub.HubServiceManager;
import insight.google.game.era.core.hub.PendingEvents;
import insight.google.game.era.core.hub.UserEvents;
import insight.google.game.era.data.AppDataManagerFactory;
import insight.google.game.era.data.GameUserDataManager;
import insight.google.game.era.data.RoomDataManager;
import insight.google.game.era.data.User;
import insight.google.game.era.data.UserDataManager;
import insight.google.game.era.data.AppDataManagerFactory.DataManager;
import insight.google.game.era.data.policys.Policy;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.appengine.api.datastore.Key;

@PersistenceCapable(identityType = IdentityType.APPLICATION,detachable="true")
public class FlowManager {
    
	private static final Log log = LogFactory.getLog(FlowManager.class);
    
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	@PrimaryKey
	private Key roomId;
	
//	@Persistent
//	private List<Key> userIdList;
//	
//	@Persistent
//	private Key currentUserId;

	@Persistent
    private boolean hasAnswer = false;

	
	
//	private GameRoom currentRoom;
//	
//	@NotPersistent
//    private PlayerClientProxy playerClientProxy;
    
//	@NotPersistent
//    private List<Map> requestList = new ArrayList<Map>();
//
//	@NotPersistent
//    private List<GameUser> roomUserList;
//	
//	@Persistent
//    GameUser currentUser;
	
    @NotPersistent
	//private GameLogManager gameLogManager = null;
	    
    //task key
    public final static String KEY_ORIGINAL = "original";
    public final static String KEY_TARGET = "target";
    public final static String KEY_COMPONENT_JS = "componentJS";
    public final static String KEY_REQUEST_CARD = "requestCard";
 
    public FlowManager(GameRoom room){
        //currentRoom = room;
        roomId = room.getRoomId();
        this.init();
    }
    
    
    private void init(){
//        GameUser currentUser =  currentRoom.getKingUser();
//        currentUserId = currentUser.getId();
    }

    /**
     *  reset user list, when have user is out.
     */
    public void resetUser(){
//        roomUserList = currentRoom.getUsers();
    }
    
    public GameUser startGame(GameUser currentUser, String jsComponentId){

    	//set default active cards to user
        List<String> activeCards = new ArrayList<String>();
        for(int i=0; i<GameRoom.initActiveCards.length; i++){
            activeCards.add(GameRoom.initActiveCards[i]);
        }
    	//get start card and send to user
        GameRoom currentRoom = currentUser.getCurrentRoom();
		ArrayList<GameCard> startCards = currentRoom.getStartCard(2);
		currentUser.addGameCard(startCards, jsComponentId);
		currentUser.setActiveCards(activeCards, jsComponentId);
        currentUser.setActive(true);
        
        GameLogManager gameLogManager = currentRoom.getGameLogManager();
        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " got starting game cards, game has started"));

        System.out.println("currentUser" + currentUser.getName() + ";startGame startCards" + startCards.size() + ";" + startCards.toString());
        
        currentUser.readyToPlay(jsComponentId);
        
        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " is Active user"));
		gameLogManager.broadcastGameActionLog();

		return currentUser;

////    	GameUser tmpUser =  Util.getUserBySession(); //getCurrentUser();
//    	GameUser currentUser = currentRoom.getCurrentUserByName();
//    	
//    	
//    	Util.getUserScriptSession(currentUser.getName());
//    	//set default active cards to user
//        List<String> activeCards = new ArrayList<String>();
//        for(int i=0; i<GameRoom.initActiveCards.length; i++){
//            activeCards.add(GameRoom.initActiveCards[i]);
//        }
//    	//get start card and send to user
//		ArrayList<GameCard> startCards = currentRoom.getStartCard(2);
////        currentUser.addGameCard(startCards,jsComponentId);
//		currentRoom.addCardsToUser(startCards, activeCards,currentUser, jsComponentId);
//        currentUser.setActive(true);
//        currentUser.setActiveCards(activeCards,jsComponentId);
//        
//        GameLogManager gameLogManager = currentRoom.getGameLogManager();
//        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " got starting game cards, game has started"));
//
//        System.out.println("currentUser" + currentUser.getName() + ";startGame startCards" + startCards.size() + ";" + startCards.toString());
//        
//        currentUser.readyToPlay(jsComponentId);
//        //currentRoom.notifyActiveUser(currentUser);
//        
//        try {
////			currentRoom.publicData(new User());
//			log.debug("room version data  ###   "+ currentRoom.getDataVersion());
//		} catch (InsightException e) {
//			e.printStackTrace();
//		}
//        
//        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " is Active user"));
//		gameLogManager.broadcastGameActionLog();
//		AppDataManagerFactory.getInstance().getDataManager(DataManager.ROOM_DATA_MANAGER.toString(),Util.createTranscationHandler()).addToDataStore(this.currentRoom);
////		GameUserDataManager gameUserDataManager = (GameUserDataManager) AppDataManagerFactory.getInstance().getDataManager(DataManager.GAMEUSER_DATA_MANAGER.toString());
////		gameUserDataManager.addToDataStore(currentUser);
////		GameUser  user = gameUserDataManager.findByName(currentUser.getName());
//		return currentUser;
    }
    
//    private GameUser getCurrentUser(){
//    	GameUserDataManager userDataManager = (GameUserDataManager)AppDataManagerFactory.getInstance().getDataManager(DataManager.GAMEUSER_DATA_MANAGER.toString(),Util.createTranscationHandler());
//    	return userDataManager.findById(this.currentUserId);
//    }
//   
    
    
    public void finishPlay(String jsComponentId,GameRoom room, GameUser currentUser){
    	currentUser.setClientActive(false, jsComponentId);
    		//currentRoom = room;
    		//currentRoom = currentUser.getCurrentRoom();
        if(currentUser.getState() == GameUser.STATE_DROP){
        	//do drop step
        	//set active cards
            List<String> activeCards = new ArrayList<String>();
            for(int i=0; i<GameRoom.allActiveCards.length; i++){
                activeCards.add(GameRoom.allActiveCards[i]);
            }
            currentUser.setActiveCards(activeCards,jsComponentId);
            
            //active user to drop
            int userBlood = currentUser.getBlood();
            //Collection<GameCard> userCards = currentUser.getGameCards2();
            int userCard = currentUser.cardCount();
            int dropCardCount = userCard - userBlood;
            dropCardCount = dropCardCount>0?dropCardCount:0;
            if(currentUser.getScriptProxy() != null){
    			PlayerClientProxyImpl.getInstance().selectDropCard(currentUser.getScriptProxy(), jsComponentId,dropCardCount);
    		}
            GameLogManager gameLogManager = room.getGameLogManager();
            gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " is selecting cards to drop"));
    		gameLogManager.broadcastGameActionLog();
            return;
        }
        
        if(currentUser.getScriptProxy() != null){
			PlayerClientProxyImpl.getInstance().finishDropCard(currentUser.getScriptProxy(), jsComponentId);
		}
        currentUser.setActive(false);
        GameLogManager gameLogManager = room.getGameLogManager();
//        
        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " has droped cards"));
		gameLogManager.broadcastGameActionLog();

		//get next user
        GameUser nextUser = this.getNextUser(room, currentUser);
        
        nextUser.setOnTurn(true);
        nextUser.setActive(true);
        nextUser.setState(GameUser.STATE_ON_TRUN);
    }
    
    public GameUser getNextUser(GameRoom room, GameUser currentUser){
        GameUser next = null;
		List<GameUser> userList = new ArrayList<GameUser>();
		//check user's active 
		for(GameUser user : room.getUserList()){
			if(GameUser.STATE_DEAD != user.getState()){
				userList.add(user);
			}
		}
        for(int i=0; i<userList.size(); i++){
            GameUser user = userList.get(i);
            if(currentUser.getName().equals(user.getName())){
                int index = 0;
                if(i < userList.size()-1){
                    index = i+1;
                }
                next = userList.get(index);
                break;
            }
        }
        return next;
    }
    
    public void requestUserOutputCard(List<GameUser> userList, String requestCardName,String jsComponentId,String senderName ){
        for(GameUser user : userList){
        	hasAnswer = false;
//        	user.requestUserExe(requestCardName, jsComponentId, "doUserRequestCard", senderName);
        	while(!hasAnswer){
        		try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        	}
        }
    }
    
    public void execRequestCard(){
//    	Map requestMap = requestList.get(0);
//    	String senderName = (String)requestMap.get(KEY_ORIGINAL);
//    	String jsComponentId = (String)requestMap.get(KEY_COMPONENT_JS);
//    	String requestCardName = (String)requestMap.get(KEY_REQUEST_CARD);
//    	GameUser tagUser = (GameUser)requestMap.get(KEY_TARGET);
//    	tagUser.requestUserExe(requestCardName, jsComponentId, "doUserRequestCard", senderName);
    }

	public boolean isHasAnswer() {
		return hasAnswer;
	}

	public void setHasAnswer(boolean hasAnswer) {
		this.hasAnswer = hasAnswer;
	}
	
	public void onTurn(GameRoom room, GameUser currentUser, String jsComponentId){
        GameLogManager gameLogManager = room.getGameLogManager();
//
        gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " is Active user"));
		
    	//set default active cards to user
        List<String> activeCards = new ArrayList<String>();
        for(int i=0; i<GameRoom.initActiveCards.length; i++){
            activeCards.add(GameRoom.initActiveCards[i]);
        }
        
        //check user blood
        CharacterCard curCharacter = currentUser.getCharacterCard();
        if(currentUser.getBlood() < curCharacter.getBlood()){
            activeCards.add("milk");
        }
        currentUser.setActiveCards(activeCards,jsComponentId);
        
        //execute character on turn policy
		List<Integer> chaPolicy = curCharacter.getPolicyList();
		int type = 0;
		for(int policyId : chaPolicy){
			Policy policy = PolicyFactory.getInstance(policyId);
			if(policy instanceof CharacterPolicy){
				type = ((CharacterPolicy)policy).getType();
				if(type == CharacterPolicy.TYPE_ON_TURN){
					GameUser[] users = new GameUser[1];
					users[0] = currentUser; 
					((CharacterPolicy)policy).beSelectedExec( currentUser, users, null);
				}
			}
		}

    	//get start card and send to user
        ArrayList<GameCard> startCards = room.getStartCard(curCharacter.getPlayCardCount());
        currentUser.addGameCard(startCards,jsComponentId);
        currentUser.setActive(true);
//		gameLogManager.addGameLog(new GameActionLog(currentUser.getName() + " recieved game cards"));
		currentUser.readyToPlay(jsComponentId);
	}
}
